<template>
  <div>
    <MyMenu></MyMenu>
    <canvas id="go" width="1920" @mousedown="prePlay" height="940"></canvas>
    <Modal
        v-model="modalBoardControl"
        title="检测到用户修改了棋谱"
        @on-ok="boardControlOk"
        @on-cancel="boardControlCancel">
      <p>是否从当前局面继续对局?</p>
    </Modal>

    <Modal
        v-model="modalCheckWinner"
        title="胜负判断"
        @on-ok="setWinnerModal"
        @on-cancel="setWinnerModal"
        >
      <p>黑:{{ this.blackWin }}</p>
      <p>白:{{ this.whiteWin }}</p>
      <p>结果为:{{ this.text }}</p>
    </Modal>
    <MyTool></MyTool>
    <MySet></MySet>
  </div>
</template>

<script>
import _ from "lodash";
import MyMenu from "./Menu.vue";
import MyTool from "./Tool.vue";
import MySet from "./Setup.vue";
import Bus from "emitvue";
import tcp from "./Tcp.vue";
import settings from "electron-settings";
import influence from '@sabaki/influence'
import * as util from './util.js'
import go from './go.js'

import * as constant from './constant'

let sound = document.body.appendChild(document.createElement("span"));
sound.play = function () {
  this.innerHTML="<embed src='play.wav' id='sound'/>";
  document.getElementById("sound").style.display='block';
  document.getElementById("sound").style.display='none';
};

export default {
  components: {
    MyMenu,
    MyTool,
    MySet,
  },
  data() {
    return {
      config: null,
      event: null,
      //是否打开修改配置的窗口
      showModal: false,
      //目前棋盘上的棋串
      string: {
        black: {},
        white: {},
        //棋串编号
        num: 19,
      },
      boardSize: 19,
      //打劫的位置
      robX: null,
      robY: null,
      //当前步位置
      siteX: -1,
      siteY: -1,
      //落子样式
      step: "step",
      //黑棋颜色
      black: "#000000",
      //白棋颜色
      white: "#FFFFFF",
      //棋盘偏移量
      offsetX: 580,
      offsetY: 120,
      //目前是否是黑棋
      isBlack: true,
      //canvas
      go: null,
      context: null,
      //棋盘 0为空 1为黑棋 -1为白棋
      board: util.getEmptyGoban(),
      goban: [], //棋谱 格式 {x,y,color}
      //目前的手数
      currentNum: -1,
      // 历史信息
      history: [],//{board:[],string{}}
      canvasData: null,
      //锁定落子
      lockedBlack: null, // null交替 1 黑 -1 白
      modalBoardControl: false, //棋盘操作后的对话框
      showXY: true,
      x: null,
      y: null,
      modalCheckWinner: false,
      blackWin: 0,
      whiteWin: 0,
      text: ''
    };
  },
  async created() {
    this.config = await settings.get("setting");
    try {
      JSON.parse(this.config)
      this.config = JSON.parse(this.config)
    } catch (err) {
      console.log("this.config或许不是一个json")
    }
  },
  async mounted() {
    this.go = document.getElementById("go");
    this.context = this.go.getContext("2d");
    this.drawMap();
    this.drawStar();
    this.drawText();

    Bus.$on("newGame", () => {
      console.log("1111 :>> ");
    });
    //切换落子
    Bus.$on("switchLock", (value) => {
      this.lockedBlack = value;
    });
    // 落子绘制控制
    Bus.$on("stepControl", (value) => {
      this.step = value;
      this.refresh();
      if (this.currentNum === -1) {
        console.log("无需绘制落子");
        return;
      }
      let current = this.history[this.currentNum]
      console.log("stepControl current ", current)
      this.switchDrawRadio(current.siteX, current.siteY);
    });
    // 引擎分析
    Bus.$on("analyze", async () => {
      let data = {
        operator: "run",
        board: _.cloneDeep(this.board),
        color: this.isBlack ? "black" : "white",
        string: _.cloneDeep(this.string),
        goban: _.cloneDeep(this.goban),
      };
      console.log(`ip = ${this.config.ip} port = ${this.config.port}`)
      let res = await tcp.send(data, this.config.ip, this.config.port);
      console.log("引擎分析结果为 :>> ", res);
      if (!res) {
        this.$Message.error("引擎传输数据格式错误!");
      }
      let probas = res.data
      let num = Math.ceil(Math.random()*1000000000%9);
      console.log("Honinbo选点->",num)
      let best = probas[num]
      let x = best.x
      let y = best.y
      console.log("引擎选点-> ", x, y)
      this.play(x, y)
    });
    // 保存棋谱至引擎
    Bus.$on("saveGoban", async () => {
      let data = {
        operator: "saveGoban",
        goban: JSON.stringify(this.goban),
      };
      let res = await tcp.send(data, config.ip, config.port);
      console.log("保存棋谱结果 :>> ", res);
      if (!res) {
        this.$Message.error("引擎传输数据格式错误!");
      } else {
        this.$Message.info(res.message);
      }
    });

    //局面分析
    Bus.$on("boardAnalyze", () => {
      this.getInfluence();
    });

    //导入棋谱
    Bus.$on("addSgf", (value) => {
      this.doSGF(value);
    });

    // 棋盘按钮控制
    Bus.$on('boardControl', (type) => {
      this.doBoardControl(type)
    });
    Bus.$on('changeShowXY', (value) => {
      this.showXY = value;
      this.refresh();
    })
    //判断胜负
    Bus.$on('checkWinner', () => {
      this.checkWinner();
    })

  },
  methods: {
    // 判断是否展示修改棋谱的对话框
    prePlay(event) {
      this.event = event
      if (this.currentNum === -1 && this.history.length === 0) {
        this.play();
        return;
      }
      if ((this.currentNum !== this.history.length - 1) && (this.currentNum !== -1 && this.history.length !== 0)) {
        console.log("this.currentNum !== this.history.length ->", this.currentNum, this.history.length);
        this.modalBoardControl = true;
      } else {
        this.play()
      }
    },
    newGame() {
      console.log("开始新游戏 ");
      this.board = util.getEmptyGoban()
      this.string = {
        black: {},
        white: {},
        //棋串编号
        num: 19,
      }
      this.robX = null;
      this.robY = null;
      this.isBlack = true;
      this.goban = []; //棋谱 格式 {x,y,color}
      //目前的手数
      this.currentNum = -1;
      // 历史信息
      this.history = [];
    },
    //画棋盘
    drawMap() {
      this.context.fillStyle = "#FFE4C4";
      this.context.fillRect(0, 0, 1920, 940);
      //棋盘纵横线
      //起点是580，120
      for (let i = 0; i < 19; i++) {
        this.context.beginPath();
        this.context.lineWidth = 0.3;
        this.context.moveTo(40 * i + this.offsetX, 0 + this.offsetY);
        this.context.lineTo(40 * i + this.offsetX, 40 * 18 + this.offsetY);
        this.context.closePath();
        this.context.stroke();

        this.context.beginPath();
        this.context.lineWidth = 0.3;
        this.context.moveTo(0 + this.offsetX, 40 * i + this.offsetY);
        this.context.lineTo(40 * 18 + this.offsetX, 40 * i + this.offsetY);
        this.context.closePath();
        this.context.stroke();
      }
    },
    play(out_x, out_y) {
      let event = this.event
      console.log('\n\n\n开始落子...');
      let tempString = _.cloneDeep(this.string);
      let tempBoard = _.cloneDeep(this.board);
      let x = out_x !== undefined ? out_x : event.layerX;
      let y = out_y !== undefined ? out_y : event.layerY;
      this.isBlack =
          this.lockedBlack === null ? this.isBlack : this.lockedBlack;
      // 引擎选点和玩家选点 一个有偏移量一个没有
      if (out_x === undefined && out_y === undefined) {
        if (
            x < this.offsetX ||
            x > this.offsetX + 40 * 19 ||
            y < this.offsetY ||
            y > this.offsetY + 40 * 19
        ) {
          this.$Message.error("请在棋盘上选择正确的点");
          return;
        }
        x = x - this.offsetX;
        y = y - this.offsetY;
        //四舍五入 修正坐标
        x = Math.round(x / 40);
        y = Math.round(y / 40);
      }

      console.log("落子前的string为 this.string :>> ", tempString);
      if (this.board[x][y] !== 0) {
        this.$Message.error("无法在已有棋子的位置落子");
        return;
      }
      // if (x === this.robX && y === this.robY) {
      //   this.$Message.error("无法在打劫点落子，请先去别处落子");
      //   return;
      // }
      console.log("落子点为x,y = ", x + 1, ",", y + 1);
      this.board[x][y] = this.isBlack ? 1 : -1;
      this.x = x;
      this.y = y;

      go.combine(x, y, this.string, this.board, this.isBlack);
      console.log("combine 后this.string :>> ", _.cloneDeep(this.string));
      let killRes = go.kill(x, y, this.board[x][y] === 1 ? -1 : 1, this.string, this.board);
      //清除死棋串
      if (killRes.length > 0) {
        for (let i = 0; i < killRes.length; i++) {
          let temp = go.cleanString(killRes[i], this.string, this.board);
          let killed = temp.killed
          this.string = temp.string
          this.board = temp.board
          if (killed.length === 1) {
            if (x === this.robX && y === this.robY) {
              this.$Message.error("无法在打劫点落子，请先去别处落子");
              this.string = tempString;
              this.board = tempBoard;
              return;
            } else {
              //记录打劫点
              this.robX = killed[0].x;
              this.robY = killed[0].y;
              console.log("记录打劫点 x=", this.robX, '  y=', this.robY);
            }
          } else {
            this.robX = null;
            this.robY = null;
          }
        }
        this.refresh();
      } else {
        //判断落子会不会导致自己死棋
        let res = go.checkKill(x, y, this.board[x][y] === 1 ? 1 : -1, this.string, this.board);
        if (res !== false) {
          this.$Message.error("无法在导致自己死棋的位置落子！");
          this.string = tempString;
          this.board = tempBoard;
          return;
        }
        this.robX = null;
        this.robY = null;
      }
      this.drawChess(x, y);
      this.siteX = x;
      this.siteY = y;
      // 反转颜色 因为刚落黑子 会直接把this.isBlack变成白，但这里插入的是上一手
      this.goban.push({x, y, color: this.isBlack ? -1 : 1});
      this.refresh();
      console.log("this.goban :>> ", this.goban);
      this.currentNum++;
      let historyPush = {
        string: _.cloneDeep(this.string),
        board: _.cloneDeep(this.board),
        robX: this.robX,
        robY: this.robY,
        //当前步位置
        siteX: this.siteX,
        siteY: this.siteY,
      }
      this.history.push(historyPush)
      console.log("history中插入了,", historyPush)
      // 是否绘制棋串号
      // this.paintNum();
      this.switchDrawRadio(x, y);

    },
    //画星点
    drawStar() {
      this.drawSingleStar(3, 3);
      this.drawSingleStar(3, 15);
      this.drawSingleStar(15, 3);
      this.drawSingleStar(15, 15);
      this.drawSingleStar(9, 9);
      this.drawSingleStar(3, 9);
      this.drawSingleStar(9, 3);
      this.drawSingleStar(9, 15);
      this.drawSingleStar(15, 9);
    },
    drawSingleStar(x, y) {
      this.context.beginPath();
      this.context.fillStyle = this.black;

      this.context.arc(
          x * 40 + this.offsetX,
          y * 40 + this.offsetY,
          3,
          0,
          2 * Math.PI
      );
      this.context.stroke();
      this.context.closePath();
      this.context.fill();
    },
    drawChess(x, y, black) {
      let ifBlack = this.board[x][y] === 1;
      this.context.beginPath();

      if (ifBlack === true) {
        this.context.fillStyle = this.black;
        this.context.strokeStyle = this.black;

        if (black === undefined) {
          this.isBlack = false;
        }
      } else {
        //白棋加点描边效果好
        this.context.fillStyle = this.white;
        this.context.strokeStyle = this.black;
        if (black === undefined) {
          this.isBlack = true;
        }
      }

      this.context.arc(
          x * 40 + this.offsetX,
          y * 40 + this.offsetY,
          17,
          0,
          2 * Math.PI
      );
      this.context.stroke();
      this.context.closePath();
      this.context.fill();
      sound.play();
    },
    //画下面的数字和字母
    drawText() {
      if (!this.showXY) {
        return;
      }
      // 预先配置好的坐标
      this.context.font = "26px Arial bolder"
      this.context.fillStyle = 'black'
      for (let key in constant.drawTextSet) {
        let textInfo = constant.drawTextSet[key]
        this.context.fillText(key, textInfo.x1, textInfo.y1)
        this.context.fillText(key, textInfo.x2, textInfo.y2)

      }
    },
    drawBoard() {
      //遍历 绘制所有的棋子
      for (let i = 0; i < 19; i++) {
        for (let j = 0; j < 19; j++) {
          if (this.board[i][j] !== 0) {
            let black = this.board[i][j] === 1;
            this.drawChess(i, j, black);
          }
        }
      }
    },
    //刷新棋盘
    refresh() {
      this.drawMap();
      this.drawStar();
      this.drawBoard();
      this.drawText()
      this.switchDrawRadio(this.x, this.y)
    },

    //把这步棋从棋盘上去掉，类似于悔棋
    /**
     * @deprecated
     * @description 存在bug 因为先combine会影响到棋串
     */
    suicide(x, y) {
      let color = this.board[x][y] === 1 ? "black" : "white";
      let num = this.string[color][x][y];
      let arr = this.string[color][num];
      console.log("需要去除点x,y :>> ", x, y);
      //把这个棋子从棋串管理对象去除
      for (let i = 0; i < arr.length; i++) {
        if (arr[i].x === x && arr[i].y === y) {
          arr.splice(i, 1);
          break;
        }
      }
      this.board[x][y] = 0;
      delete this.string[color][x][y];
    },
    // 给棋子标注棋串号 debug用
    paintNum() {
      for (let i = 0; i < 19; i++) {
        for (let j = 0; j < 19; j++) {
          if (this.board[i][j] !== 0) {
            let textColor = this.board[i][j] === 1 ? "#FFFFFF" : "#000000";
            let color = this.board[i][j] === 1 ? "black" : "white";
            let num = this.string[color][i][j];
            this.context.fillStyle = textColor;
            this.context.font = "20px Arial";
            this.context.fillText(
                num.toString(),
                this.offsetX - 10 + i * 40,
                this.offsetY + 10 + j * 40
            );
          }
        }
      }
    },
    //绘制单个落子手数
    drawSingleStep(i, j, num) {
      let offsetText=0;
        num=num || this.goban.length;
        if(num < 10) offsetText = 5;
        if(num > 100) offsetText = -5;
        if(this.board[i][j] !== 0){
          let textColor = (this.board[i][j] === 1 ? this.white : this.black);
          this.context.fillStyle = textColor;
          this.context.font = "20px Arial";
          this.context.fillText(num.toString(), i * 40 - 10 + this.offsetX + offsetText, j * 40 + 10 + this.offsetY);
        }
    },
    //根据单选框来绘制当前图像
    switchDrawRadio(x, y) {
      x = x || this.x;
      y = y || this.y;
      switch (this.step) {
        case "step":
          this.drawCurrentRect(x, y);
          break;
        case "currentStep":
          this.drawSingleStep(x, y);
          break;
        case "hands":
          this.drawStep();
          break;
        default:
          break;
      }
    },
    // 绘制当前落子的标志
    drawCurrentRect(x, y) {
      console.log("绘制当前落子 :>> ");
      this.context.beginPath();
      this.context.fillStyle = this.board[x][y] === 1 ? "#FFFFFF" : "#000000";

      this.context.arc(
          x * 40 + this.offsetX,
          y * 40 + this.offsetY,
          7,
          0,
          2 * Math.PI
      );
      this.context.closePath();

      this.context.fill();
    },
    //画圆
    drawCircle(x, y, radius, color) {
      this.context.beginPath();
      this.context.fillStyle = color;
      this.context.arc(
          x * 40 + this.offsetX,
          y * 40 + this.offsetY,
          radius,
          0,
          2 * Math.PI
      );
      this.context.closePath();

      this.context.fill();
    },
    //绘制手数
    drawStep() {
      let needDraw = {}; //需要绘制的列表 用对象数据结构
      for (let i = 0; i < this.goban.length; i++) {
        let x = this.goban[i].x;
        let y = this.goban[i].y;
        //如果为空说明被吃了
        if (this.board[x][y] !== 0) {
          if (!needDraw[x]) {
            needDraw[x] = {};
          }
          if (!needDraw[x][y]) {
            needDraw[x][y] = {
              num: i + 1,
            };
          } else {
            //小了说明曾经存在但被吃了 且吃完还被一方填子了
            if (needDraw[x][y].num < i + 1) {
              needDraw[x][y] = {
                num: i + 1,
              };
            }
          }
        }
      }

      for (let x in needDraw) {
        for (let y in needDraw[x]) {
          let info = needDraw[x][y];
          this.drawSingleStep(x, y, info.num);
        }
      }
    },
    // 形式判断
    getInfluence() {
      let res = influence.map(this.board);
      console.log('res :>> ', res);
      for (let i = 0; i < 19; i++) {
        for (let j = 0; j < 19; j++) {
          let value = res[i][j];
          if (value === 0 || value === 1 || value === -1) {
            // 这种不需要绘制影响力
            continue;
          }
          value = parseFloat(value.toString().slice(0, 4))
          let color = null;
          if (value > 0) {
            color = "#000000"
          } else {
            color = "#FFFFFF"
          }
          if (value < 0) {
            value = -value;
          }
          value *= 10
          this.drawCircle(i, j, value, color)
        }
      }
    },
    // 处理传来的sgf解析完成的数据
    doSGF(sgfData) {
      console.log("传来的sgf为 ", sgfData)
      this.newGame();
      for (let i = 0; i < sgfData.length; i++) {
        let {x, y, color} = sgfData[i];
        this.goban.push({x, y, color: color === 'black' ? 1 : -1})
        //棋谱的x,y都大一个
        x--;
        y--;
        console.log(`目前是第${i}手`, "   x,y,color,", x, y, color);
        this.sgfLogical(x, y, color);
      }
      console.log("this.string", this.string)
      console.log("this.board", this.board)
      console.log("this.goban", this.goban)
      this.refresh();
    },
    // sgf棋谱的围棋逻辑 即不需要考虑自身死棋，越界等问题
    sgfLogical(x, y, color) {
      this.isBlack = color === 'black';
      this.board[x][y] = this.isBlack ? 1 : -1;
      go.combine(x, y, this.string, this.board, this.isBlack)
      let killRes = go.kill(x, y, this.board[x][y] === 1 ? -1 : 1, this.string, this.board);
      //清除死棋串
      if (killRes.length > 0) {
        for (let i = 0; i < killRes.length; i++) {
          go.cleanString(killRes[i], this.string, this.board);
        }
      }
    },

    //棋盘控制
    doBoardControl(type) {
      console.log("doBoardControl处理前,currentNum = ", this.currentNum)
      console.log('type = ', type)
      // 对当前手数进行操作
      switch (type) {
        case 'begin':
          if (this.currentNum === -1) {
            this.$Message.warning("已经到最开始的位置")
            return;
          }
          this.currentNum = -1;
          break;
        case 'fback':
          if (this.currentNum === -1) {
            this.$Message.warning("已经到最开始的位置")
            return;
          }
          this.currentNum = this.currentNum - 5;
          break;
        case 'back':
          if (this.currentNum === -1) {
            this.$Message.warning("已经到最开始的位置")
            return;
          }
          this.currentNum--;
          break;
        case 'step':
          if (this.currentNum === this.history.length - 1) {
            this.$Message.warning("已经到最末尾的位置")
            return;
          }
          this.currentNum++;
          break;
        case 'fstep':
          if (this.currentNum === this.history.length - 1) {
            this.$Message.warning("已经到最末尾的位置")
            return;
          }
          this.currentNum = this.currentNum + 5;
          break;
        case 'end':
          if (this.currentNum === this.history.length - 1) {
            this.$Message.warning("已经到最末尾的位置")
            return;
          }
          this.currentNum = this.history.length - 1;
          break;
      }

      //防止越界
      this.currentNum = this.currentNum >= -1 ? this.currentNum : -1;
      this.currentNum = this.currentNum <= this.history.length - 1 ? this.currentNum : this.history.length - 1;
      console.log('this.currentNum = ', this.currentNum)
      this.updateBoardData();
      console.log('处理后this.string = ', this.string)
      console.log('处理后this.board = ', this.board)
      this.refresh();
      if (this.currentNum === -1) {
        return;
      }
      this.switchDrawRadio(this.siteX, this.siteY);
    },

    // 更新棋盘数据
    updateBoardData() {
      console.log(' updateBoardData this.currentNum = ', this.currentNum)
      console.log("this.history[this.currentNum]", this.history[this.currentNum])
      if (this.currentNum === -1) {
        this.board = util.getEmptyGoban();
        this.string = util.getEmptyString();
        this.robX = null;
        this.robY = null;
        this.siteX = null;
        this.siteY = null;
      } else {
        this.string = this.history[this.currentNum].string;
        this.board = this.history[this.currentNum].board;
        this.robX = this.history[this.currentNum].robX;
        this.robY = this.history[this.currentNum].robY;
        this.siteX = this.history[this.currentNum].siteX;
        this.siteY = this.history[this.currentNum].siteY;
      }
    },

    // 用户先改了棋盘 再落子，就会进行提示
    boardControlOk() {
      // 截断历史
      if (this.currentNum !== -1) {
        this.history = this.history.slice(0, this.currentNum)
        this.currentNum--;
      } else {
        this.history = [];
      }
      this.play();
      this.$Message.success('已修改历史棋谱');
    },
    boardControlCancel() {
      this.$Message.info('暂未修改棋谱');
    },
    checkWinner() {
      let res = influence.areaMap(this.board);
      console.log("判断胜负结果为,res->", res);
      let black = 0;
      let white = 0;
      for (let i = 0; i < 19; i++) {
        for (let j = 0; j < 19; j++) {
          if (res[i][j] === 1) {
            black++;

          } else if (res[i][j] === -1) {
            white++;
          }
        }
      }
      let text = '';
      if (black > white + 6.5) {
        text = '黑胜';
      } else {
        text = '白胜';
      }

      console.log('black = ', black);
      console.log('white = ', white);
      this.blackWin = black;
      this.whiteWin = white;
      this.text = text;
      this.modalCheckWinner = true;
      console.log("this.modalCheckWinner",this.modalCheckWinner)
    },
    setWinnerModal() {
      this.modalCheckWinner = !this.modalCheckWinner;
    },
  },
};
</script>

<style>
</style>
